﻿using MockDataAccess;
using MockDataTransferObject;
using System.Data;
using MockCommon;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace MockBusiness
{
    public class ContractBusiness
    {
        #region Initialize
        private static ContractBusiness _instance;
        private readonly ContractDataAccess _contractDataAccess;
        private readonly ConsultantDataAccess _consultantDataAccess;
        private readonly UserDataAccess _userDataAccess;
        private readonly ContractorDataAccess _contractorDataAccess;
        private readonly ClientDataAccess _clientDataAccess;
        private readonly ContractTypeDataAccess _contractTypeDataAccess;

        /// <summary>
        /// Gets the contract data test.
        /// </summary>
        public Collection<Contract> ContractDataTest
        {
            get
            {
                return _contractDataAccess.AffectedRows;
            }
        }

        /// <summary>
        /// Gets the consultant data test.
        /// </summary>
        public Collection<Consultant> ConsultantDataTest
        {
            get
            {
                return _consultantDataAccess.AffectedRows;
            }
        }

        /// <summary>
        /// Gets the user data test.
        /// </summary>
        public Collection<User> UserDataTest
        {
            get
            {
                return _userDataAccess.AffectedRows;
            }
        }

        /// <summary>
        /// Gets the contractor data test.
        /// </summary>
        public Collection<Contractor> ContractorDataTest
        {
            get
            {
                return _contractorDataAccess.AffectedRows;
            }
        }

        /// <summary>
        /// Gets the client data test.
        /// </summary>
        public Collection<Client> ClientDataTest
        {
            get
            {
                return _clientDataAccess.AffectedRows;
            }
        }

        /// <summary>
        /// Gets the contract type data test.
        /// </summary>
        public Collection<ContractType> ContractTypeDataTest
        {
            get
            {
                return _contractTypeDataAccess.AffectedRows;
            }
        }

        /// <summary>
        /// Prevents a default instance of the <see cref="ContractBusiness"/> class from being created.
        /// </summary>
        private ContractBusiness()
        {
            _contractDataAccess = new ContractDataAccess();
            _contractorDataAccess = new ContractorDataAccess();
            _consultantDataAccess = new ConsultantDataAccess();
            _userDataAccess = new UserDataAccess();
            _clientDataAccess = new ClientDataAccess();
            _contractTypeDataAccess = new ContractTypeDataAccess();
        }

        /// <summary>
        /// Prevents a default instance of the <see cref="ContractBusiness"/> class from being created.
        /// </summary>
        /// <param name="isFake">if set to <c>true</c> [is fake].</param>
        private ContractBusiness(bool isFake)
        {
            _contractDataAccess = new ContractDataAccess(isFake);
            _contractorDataAccess = new ContractorDataAccess(isFake);
            _consultantDataAccess = new ConsultantDataAccess(isFake);
            _userDataAccess = new UserDataAccess(isFake);
            _clientDataAccess = new ClientDataAccess(isFake);
            _contractTypeDataAccess = new ContractTypeDataAccess(isFake);
        }

        /// <summary>
        /// Retrieves the instance.
        /// </summary>
        /// <returns></returns>
        public static ContractBusiness RetrieveInstance()
        {
            if (_instance == null)
                _instance = new ContractBusiness();
            return _instance;
        }

        /// <summary>
        /// Retrieves the instance.
        /// </summary>
        /// <param name="isFake">if set to <c>true</c> [is fake].</param>
        /// <returns></returns>
        public static ContractBusiness RetrieveInstance(bool isFake)
        {
            if (_instance == null)
                _instance = new ContractBusiness(isFake);
            return _instance;
        }
        #endregion

        #region CUD
        /// <summary>
        /// Inserts the specified contract.
        /// </summary>
        /// <param name="contract">The contract.</param>
        public void Insert(Contract contract)
        {
            //Check valid contract
            if (contract == null)
            {
                throw new MockException("Contract is null", "ContractBusiness");
            }
            if (_contractDataAccess.Exist(contract.ContractId))
            {
                throw new MockException("Contract was existed", "ContractBusiness.");
            }
            if(contract.Content == null)
            {
                throw new MockException("Content is null", "ContractBusiness");
            }

            if (contract.StartDate > contract.EndDate)
            {
                throw new MockException("EndDate must greater than StartDate", "ContractBusiness");
            }
            //Check valid contractor
            Contractor contractor = contract.Contractor;
            if (contractor == null)
            {
                throw new MockException("Contractor is null", "ContractBusiness");
            }
            if (contractor.FirstName == null)
            {
                throw new MockException("FirstName is null", "ContractBusiness");
            }
            if (contractor.LastName == null)
            {
                throw new MockException("LastName is null", "ContractBusiness");
            }

            if (_contractorDataAccess.Exist(contractor.ContractorId) == true)
            {
                throw new MockException("Contractor was existed", "ContractBusiness");
            }

            if (contractor.BirthDate > contract.StartDate)
            {
                throw new MockException("StartDate must greater than BirthDate", "ContractBusiness");
            }
            User contractorUser = contractor.User;
            if (_userDataAccess.Exist(contractorUser.UserId))
            {
                throw new MockException("Contractor user is existed", "ContractBusiness");
            }
            //Check valid consultant
            Consultant consultant = contract.Consultant;
            if (consultant == null)
            {
                throw new MockException("Consultant is null", "ContractBusiness");
            }
            if (!_consultantDataAccess.Exist(consultant.ConsultantId))
            {
                throw new MockException("Consultant was not existed", "ContractBusiness");
            }
            //Check valid ContractType
            ContractType contractType = contract.ContractType;
            if (contractType == null)
            {
                throw new MockException("ContractType is null", "ContractBusiness");
            }
            if (!_contractTypeDataAccess.Exist(contractType.ContractTypeId))
            {
                throw new MockException("ContractType was not existed", "ContractBusiness");
            }
            //Check valid client
            Client client = contract.Client;
            if (client == null)
            {
                throw new MockException("Client is null", "ContractBusiness");
            }

            if (!_clientDataAccess.Exist(client.ClientId))
            {
                throw new MockException("Client was not existed", "ContractBusiness");
            }
            //Data is valid
            _contractDataAccess.Create(contract, true);

        }

        /// <summary>
        /// Updates the specified contract.
        /// </summary>
        /// <param name="contract">The contract.</param>
        public void Update(Contract contract)
        {
            if (contract == null)
            {
                throw new MockException("Contract is null", "Business");
            }
            if (_contractDataAccess.Exist(contract.ContractId) == false)
            {
                throw new MockException("Contract was not existed", "Business");
            }
            if (contract.Content == null)
            {
                throw new MockException("Contract is null", "ContractBusiness");
            }
            if (contract.StartDate > contract.EndDate)
            {
                throw new MockException("EndDate must greater than StartDate", "Business");
            }
            //Check valid contractor
            Contractor contractor = contract.Contractor;
            if (contractor == null)
            {
                throw new MockException("Contractor is null", "Business");
            }
            if (contractor.FirstName == null)
            {
                throw new MockException("FirstName is null", "ContractBusiness");
            }
            if (contractor.LastName == null)
            {
                throw new MockException("LastName is null", "ContractBusiness");
            }
            if (_contractorDataAccess.Exist(contractor.ContractorId) == false)
            {
                throw new MockException("Contractor was not existed", "Business");
            }
            Consultant consultant = contract.Consultant;
            if (consultant == null)
            {
                throw new MockException("Consultant is null", "Business");
            }
            if (!_consultantDataAccess.Exist(consultant.ConsultantId))
            {
                throw new MockException("Consultant was not existed", "Business");
            }
            //Check valid ContractType
            ContractType contractType = contract.ContractType;
            if (contractType == null)
            {
                throw new MockException("ContractType is null", "Business");
            }
            if (!_contractTypeDataAccess.Exist(contractType.ContractTypeId))
            {
                throw new MockException("ContractType was not existed", "Business");
            }
            //Check valid client
            Client client = contract.Client;
            if (client == null)
            {
                throw new MockException("Client is null", "Business");
            }

            if (!_clientDataAccess.Exist(client.ClientId))
            {
                throw new MockException("Client was not existed", "Business");
            }
            _contractDataAccess.Update(contract);
        }

        /// <summary>
        /// Deletes the specified contract id.
        /// </summary>
        /// <param name="contractId">The contract id.</param>
        public void Delete(Guid contractId)
        {
           
            if (_contractDataAccess.Exist(contractId) == false)
            {
                throw new MockException("ContractId was not existed", "Business");
            }
            _contractDataAccess.Delete(contractId);
        }
        #endregion

        #region R
        /// <summary>
        /// Retrieves all contract.
        /// </summary>
        /// <returns></returns>
        public Collection<Contract> RetrieveAllContract()
        {
            return _contractDataAccess.RetrieveAllContracts();
        }

        /// <summary>
        /// Gets the contract id by contractor user id.
        /// </summary>
        /// <param name="userId">The user id.</param>
        /// <returns></returns>
        public object GetContractIdByContractorUserId(Guid userId)
        {
            if (userId == null)
            {
                throw new MockException("userId is null", "ContractBusiness");
            }
            return _contractDataAccess.GetContractIdByUserId(userId);
        }

        /// <summary>
        /// Gets the by id.
        /// </summary>
        /// <param name="contractId">The contract id.</param>
        /// <returns></returns>
        public Contract GetById(Guid contractId)
        {
            if(contractId == null)
            {
                throw new MockException("contractId is null", "ContractBusiness");
            }
            return _contractDataAccess.GetById(contractId);
        }

        /// <summary>
        /// Gets the by consultant id.
        /// </summary>
        /// <param name="consultantId">The consultant id.</param>
        /// <returns></returns>
        public Collection<Contract> GetByConsultantId(object consultantId)
        {
            if (consultantId == null)
            {
                throw new MockException("consultantId is null", "ContractBusiness");
            }
            return _contractDataAccess.GetByConsultantId(consultantId);
        }

        /// <summary>
        /// Gets the by filter.
        /// </summary>
        /// <param name="contractTypeId">The contract type id.</param>
        /// <param name="isActive">The is active.</param>
        /// <param name="consultantId">The consultant id.</param>
        /// <returns></returns>
        public Collection<Contract> GetByFilter(object contractTypeId, object isActive, object consultantId)
        {
            return _contractDataAccess.GetByFilter(contractTypeId, isActive, consultantId);
        }
        #endregion

        #region Other
        /// <summary>
        /// Makes the content of the CSV.
        /// </summary>
        /// <param name="content">The content.</param>
        /// <returns></returns>
        public static string MakeCsvContent(string content)
        {
            string body = Constant.PatternCsvFile;
            try
            {
                string[] rows = content.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
                foreach (string row in rows)
                {
                    if (row == "\r")
                    {
                        continue;
                    }
                    string rowContent = row.Replace("\t", ",");
                    rowContent = rowContent.Replace(",\r", "");
                    body += "\n";
                    body += rowContent;
                }
            }
            catch (ArgumentNullException exception)
            {
                throw new MockException(exception.Message, "Business");
            }
            catch (ArgumentException exception)
            {
                throw new MockException(exception.Message, "Business");
            }
            return body;
        }
        #endregion
    }
}
